

module sha2_256 #(
    parameter MAX_MSG_LEN = 512
    )(
    input wire clk,
    input wire rst_n,
//    input ready,
    input wire [MAX_MSG_LEN-1:0] message_block, // 
    input  valid,
    output reg [255:0] digest,
    output valid_o,
    output reg done
);
    //----------register define----------//
    reg [31:0] w [0:63];
    reg [31:0] a, b, c, d, e, f, g, h_temp;
    integer t;
    reg [31:0] T1, T2;
//    reg [7:0] block_count;
    reg [2:0] state;
    localparam IDLE      = 3'd0,
               PROC      = 3'd1;
    reg valid_r,valid_r1;  
    reg [31:0] h [0:7];  
    reg [255:0] digest_r;
    
    //----------main code----------//
    
    
    
    always @(posedge clk or negedge rst_n)
        if(~rst_n)begin
            digest <= 0;
            valid_r <= 0;
            valid_r1 <=0;
        end
        else begin
            digest <= digest_r;
            valid_r <= valid;
            valid_r1 <= valid_r;
        end
        
    reg [31:0] k [0:63];
    integer i1;
    always @(posedge clk or negedge rst_n) begin
        if(~rst_n)
            for(i1=0;i1<64;i1=i1+1) begin
                k[i1] <= 32'h0;
            end
        else begin
            k[0 ] <= 32'h428a2f98; k[1 ] <= 32'h71374491; k[2 ] <= 32'hb5c0fbcf; k[3 ] <= 32'he9b5dba5;
            k[4 ] <= 32'h3956c25b; k[5 ] <= 32'h59f111f1; k[6 ] <= 32'h923f82a4; k[7 ] <= 32'hab1c5ed5;
            k[8 ] <= 32'hd807aa98; k[9 ] <= 32'h12835b01; k[10] <= 32'h243185be; k[11] <= 32'h550c7dc3;
            k[12] <= 32'h72be5d74; k[13] <= 32'h80deb1fe; k[14] <= 32'h9bdc06a7; k[15] <= 32'hc19bf174;
            k[16] <= 32'he49b69c1; k[17] <= 32'hefbe4786; k[18] <= 32'h0fc19dc6; k[19] <= 32'h240ca1cc;
            k[20] <= 32'h2de92c6f; k[21] <= 32'h4a7484aa; k[22] <= 32'h5cb0a9dc; k[23] <= 32'h76f988da;
            k[24] <= 32'h983e5152; k[25] <= 32'ha831c66d; k[26] <= 32'hb00327c8; k[27] <= 32'hbf597fc7;
            k[28] <= 32'hc6e00bf3; k[29] <= 32'hd5a79147; k[30] <= 32'h06ca6351; k[31] <= 32'h14292967;
            k[32] <= 32'h27b70a85; k[33] <= 32'h2e1b2138; k[34] <= 32'h4d2c6dfc; k[35] <= 32'h53380d13;
            k[36] <= 32'h650a7354; k[37] <= 32'h766a0abb; k[38] <= 32'h81c2c92e; k[39] <= 32'h92722c85;
            k[40] <= 32'ha2bfe8a1; k[41] <= 32'ha81a664b; k[42] <= 32'hc24b8b70; k[43] <= 32'hc76c51a3;
            k[44] <= 32'hd192e819; k[45] <= 32'hd6990624; k[46] <= 32'hf40e3585; k[47] <= 32'h106aa070;
            k[48] <= 32'h19a4c116; k[49] <= 32'h1e376c08; k[50] <= 32'h2748774c; k[51] <= 32'h34b0bcb5;
            k[52] <= 32'h391c0cb3; k[53] <= 32'h4ed8aa4a; k[54] <= 32'h5b9cca4f; k[55] <= 32'h682e6ff3;
            k[56] <= 32'h748f82ee; k[57] <= 32'h78a5636f; k[58] <= 32'h84c87814; k[59] <= 32'h8cc70208;
            k[60] <= 32'h90befffa; k[61] <= 32'ha4506ceb; k[62] <= 32'hbef9a3f7; k[63] <= 32'hc67178f2;
        end
    end

    // 辅助函数
    function [31:0] Ch;
        input [31:0] x;
        input [31:0] y;
        input [31:0] z;
        Ch = (x & y) ^ (~x & z);
    endfunction

    function [31:0] Maj;
        input [31:0] x;
        input [31:0] y;
        input [31:0] z;
        Maj = (x & y) ^ (x & z) ^ (y & z);
    endfunction

    function [31:0] Sigma0;
        input [31:0] x;
        Sigma0 = ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10));
    endfunction

    function [31:0] Sigma1;
        input [31:0] x;
        Sigma1 = ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7));
    endfunction

    function [31:0] sigma0;
        input [31:0] x;
        sigma0 = ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ (x >> 3);
    endfunction

    function [31:0] sigma1;
        input [31:0] x;
        sigma1 = ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10);
    endfunction
    
    always @(*)
        if (~rst_n) begin
            for (t = 0; t < 64; t = t + 1) begin
                w[t] = 0;
            end
        end
        else begin
            for (t = 0; t < 16; t = t + 1) begin
                w[t] = message_block[(MAX_MSG_LEN-1 - t * 32) -: 32];
            end
            for (t = 16; t < 64; t = t + 1) begin
                w[t] = sigma1(w[t-2])+ w[t-7] + sigma0(w[t-15])+w[t-16];
            end
            /*
            w[16+8*0+0]=sigma1(w[16+8*0+0 - 2]) + w[16+8*0+0 - 7] + sigma0(w[16+8*0+0 - 15]) + w[16+8*0+0 - 16];
            w[16+8*0+1]=sigma1(w[16+8*0+1 - 2]) + w[16+8*0+1 - 7] + sigma0(w[16+8*0+1 - 15]) + w[16+8*0+1 - 16];
            w[16+8*0+2]=sigma1(w[16+8*0+2 - 2]) + w[16+8*0+2 - 7] + sigma0(w[16+8*0+2 - 15]) + w[16+8*0+2 - 16];
            w[16+8*0+3]=sigma1(w[16+8*0+3 - 2]) + w[16+8*0+3 - 7] + sigma0(w[16+8*0+3 - 15]) + w[16+8*0+3 - 16];
            w[16+8*0+4]=sigma1(w[16+8*0+4 - 2]) + w[16+8*0+4 - 7] + sigma0(w[16+8*0+4 - 15]) + w[16+8*0+4 - 16];
            w[16+8*0+5]=sigma1(w[16+8*0+5 - 2]) + w[16+8*0+5 - 7] + sigma0(w[16+8*0+5 - 15]) + w[16+8*0+5 - 16];
            w[16+8*0+6]=sigma1(w[16+8*0+6 - 2]) + w[16+8*0+6 - 7] + sigma0(w[16+8*0+6 - 15]) + w[16+8*0+6 - 16];
            w[16+8*0+7]=sigma1(w[16+8*0+7 - 2]) + w[16+8*0+7 - 7] + sigma0(w[16+8*0+7 - 15]) + w[16+8*0+7 - 16];
            w[16+8*0+8]=sigma1(w[16+8*0+8 - 2]) + w[16+8*0+8 - 7] + sigma0(w[16+8*0+8 - 15]) + w[16+8*0+8 - 16];
            
            w[16+8*1+1]=sigma1(w[16+8*1+1 - 2]) + w[16+8*1+1 - 7] + sigma0(w[16+8*1+1 - 15]) + w[16+8*1+1 - 16];
            w[16+8*1+2]=sigma1(w[16+8*1+2 - 2]) + w[16+8*1+2 - 7] + sigma0(w[16+8*1+2 - 15]) + w[16+8*1+2 - 16];
            w[16+8*1+3]=sigma1(w[16+8*1+3 - 2]) + w[16+8*1+3 - 7] + sigma0(w[16+8*1+3 - 15]) + w[16+8*1+3 - 16];
            w[16+8*1+4]=sigma1(w[16+8*1+4 - 2]) + w[16+8*1+4 - 7] + sigma0(w[16+8*1+4 - 15]) + w[16+8*1+4 - 16];
            w[16+8*1+5]=sigma1(w[16+8*1+5 - 2]) + w[16+8*1+5 - 7] + sigma0(w[16+8*1+5 - 15]) + w[16+8*1+5 - 16];
            w[16+8*1+6]=sigma1(w[16+8*1+6 - 2]) + w[16+8*1+6 - 7] + sigma0(w[16+8*1+6 - 15]) + w[16+8*1+6 - 16];
            w[16+8*1+7]=sigma1(w[16+8*1+7 - 2]) + w[16+8*1+7 - 7] + sigma0(w[16+8*1+7 - 15]) + w[16+8*1+7 - 16];
            w[16+8*1+8]=sigma1(w[16+8*1+8 - 2]) + w[16+8*1+8 - 7] + sigma0(w[16+8*1+8 - 15]) + w[16+8*1+8 - 16];
            
            w[16+8*2+1]=sigma1(w[16+8*2+1 - 2]) + w[16+8*2+1 - 7] + sigma0(w[16+8*2+1 - 15]) + w[16+8*2+1 - 16];
            w[16+8*2+2]=sigma1(w[16+8*2+2 - 2]) + w[16+8*2+2 - 7] + sigma0(w[16+8*2+2 - 15]) + w[16+8*2+2 - 16];
            w[16+8*2+3]=sigma1(w[16+8*2+3 - 2]) + w[16+8*2+3 - 7] + sigma0(w[16+8*2+3 - 15]) + w[16+8*2+3 - 16];
            w[16+8*2+4]=sigma1(w[16+8*2+4 - 2]) + w[16+8*2+4 - 7] + sigma0(w[16+8*2+4 - 15]) + w[16+8*2+4 - 16];
            w[16+8*2+5]=sigma1(w[16+8*2+5 - 2]) + w[16+8*2+5 - 7] + sigma0(w[16+8*2+5 - 15]) + w[16+8*2+5 - 16];
            w[16+8*2+6]=sigma1(w[16+8*2+6 - 2]) + w[16+8*2+6 - 7] + sigma0(w[16+8*2+6 - 15]) + w[16+8*2+6 - 16];
            w[16+8*2+7]=sigma1(w[16+8*2+7 - 2]) + w[16+8*2+7 - 7] + sigma0(w[16+8*2+7 - 15]) + w[16+8*2+7 - 16];
            w[16+8*2+8]=sigma1(w[16+8*2+8 - 2]) + w[16+8*2+8 - 7] + sigma0(w[16+8*2+8 - 15]) + w[16+8*2+8 - 16];
            
            w[16+8*3+1]=sigma1(w[16+8*3+1 - 2]) + w[16+8*3+1 - 7] + sigma0(w[16+8*3+1 - 15]) + w[16+8*3+1 - 16];
            w[16+8*3+2]=sigma1(w[16+8*3+2 - 2]) + w[16+8*3+2 - 7] + sigma0(w[16+8*3+2 - 15]) + w[16+8*3+2 - 16];
            w[16+8*3+3]=sigma1(w[16+8*3+3 - 2]) + w[16+8*3+3 - 7] + sigma0(w[16+8*3+3 - 15]) + w[16+8*3+3 - 16];
            w[16+8*3+4]=sigma1(w[16+8*3+4 - 2]) + w[16+8*3+4 - 7] + sigma0(w[16+8*3+4 - 15]) + w[16+8*3+4 - 16];
            w[16+8*3+5]=sigma1(w[16+8*3+5 - 2]) + w[16+8*3+5 - 7] + sigma0(w[16+8*3+5 - 15]) + w[16+8*3+5 - 16];
            w[16+8*3+6]=sigma1(w[16+8*3+6 - 2]) + w[16+8*3+6 - 7] + sigma0(w[16+8*3+6 - 15]) + w[16+8*3+6 - 16];
            w[16+8*3+7]=sigma1(w[16+8*3+7 - 2]) + w[16+8*3+7 - 7] + sigma0(w[16+8*3+7 - 15]) + w[16+8*3+7 - 16];
            w[16+8*3+8]=sigma1(w[16+8*3+8 - 2]) + w[16+8*3+8 - 7] + sigma0(w[16+8*3+8 - 15]) + w[16+8*3+8 - 16];
            
            w[16+8*4+1]=sigma1(w[16+8*4+1 - 2]) + w[16+8*4+1 - 7] + sigma0(w[16+8*4+1 - 15]) + w[16+8*4+1 - 16];
            w[16+8*4+2]=sigma1(w[16+8*4+2 - 2]) + w[16+8*4+2 - 7] + sigma0(w[16+8*4+2 - 15]) + w[16+8*4+2 - 16];
            w[16+8*4+3]=sigma1(w[16+8*4+3 - 2]) + w[16+8*4+3 - 7] + sigma0(w[16+8*4+3 - 15]) + w[16+8*4+3 - 16];
            w[16+8*4+4]=sigma1(w[16+8*4+4 - 2]) + w[16+8*4+4 - 7] + sigma0(w[16+8*4+4 - 15]) + w[16+8*4+4 - 16];
            w[16+8*4+5]=sigma1(w[16+8*4+5 - 2]) + w[16+8*4+5 - 7] + sigma0(w[16+8*4+5 - 15]) + w[16+8*4+5 - 16];
            w[16+8*4+6]=sigma1(w[16+8*4+6 - 2]) + w[16+8*4+6 - 7] + sigma0(w[16+8*4+6 - 15]) + w[16+8*4+6 - 16];
            w[16+8*4+7]=sigma1(w[16+8*4+7 - 2]) + w[16+8*4+7 - 7] + sigma0(w[16+8*4+7 - 15]) + w[16+8*4+7 - 16];
            w[16+8*4+8]=sigma1(w[16+8*4+8 - 2]) + w[16+8*4+8 - 7] + sigma0(w[16+8*4+8 - 15]) + w[16+8*4+8 - 16];
            
            w[16+8*5+1]=sigma1(w[16+8*5+1 - 2]) + w[16+8*5+1 - 7] + sigma0(w[16+8*5+1 - 15]) + w[16+8*5+1 - 16];
            w[16+8*5+2]=sigma1(w[16+8*5+2 - 2]) + w[16+8*5+2 - 7] + sigma0(w[16+8*5+2 - 15]) + w[16+8*5+2 - 16];
            w[16+8*5+3]=sigma1(w[16+8*5+3 - 2]) + w[16+8*5+3 - 7] + sigma0(w[16+8*5+3 - 15]) + w[16+8*5+3 - 16];
            w[16+8*5+4]=sigma1(w[16+8*5+4 - 2]) + w[16+8*5+4 - 7] + sigma0(w[16+8*5+4 - 15]) + w[16+8*5+4 - 16];
            w[16+8*5+5]=sigma1(w[16+8*5+5 - 2]) + w[16+8*5+5 - 7] + sigma0(w[16+8*5+5 - 15]) + w[16+8*5+5 - 16];
            w[16+8*5+6]=sigma1(w[16+8*5+6 - 2]) + w[16+8*5+6 - 7] + sigma0(w[16+8*5+6 - 15]) + w[16+8*5+6 - 16];
            w[16+8*5+7]=sigma1(w[16+8*5+7 - 2]) + w[16+8*5+7 - 7] + sigma0(w[16+8*5+7 - 15]) + w[16+8*5+7 - 16];
        */
        end
        
    
    always @(*) 
        if (!rst_n) begin
//            for (t = 0; t < 64; t = t + 1) begin
//                w[t] =  0;
//            end
            h[0] = 32'h0;h[1] = 32'h0;h[2] = 32'h0;h[3] = 32'h0;
            h[4] = 32'h0;h[5] = 32'h0;h[6] = 32'h0;h[7] = 32'h0;
            a = 0;
            b = 0;
            c = 0;
            d = 0;
            e = 0;
            f = 0;
            g = 0;
            h_temp =0;
            T1=0;
            T2=0;
            digest_r = 256'b0;
//            valid_r <= 0;
        end
        else if(state==IDLE)begin
            h[0] = 32'h6a09e667;
            h[1] = 32'hbb67ae85;
            h[2] = 32'h3c6ef372;
            h[3] = 32'ha54ff53a;
            h[4] = 32'h510e527f;
            h[5] = 32'h9b05688c;
            h[6] = 32'h1f83d9ab;
            h[7] = 32'h5be0cd19;
            a = h[0];
            b = h[1];
            c = h[2];
            d = h[3];
            e = h[4];
            f = h[5];
            g = h[6];
            h_temp = h[7];
        end     
        else if(state == PROC) begin
            
            
            
            for (t = 0; t < 64; t = t + 1) begin
                    T1 = h_temp + Sigma1(e) + Ch(e, f, g) + k[t] + w[t];
//                    $display("%dth %h %h %h %h %h",t,h_temp,Sigma1(e),Ch(e, f, g),k[t],w[t]);
                    T2 = Sigma0(a) + Maj(a, b, c);
//                    $display("%dth %h %h",t,Sigma0(a), Maj(a, b, c));
//                    $display("%dth,T1:%h,T2:%h",t,T1,T2);
                    h_temp = g;
//                    $display("%dth,h:%h",t,h_temp);
                    g = f;
//                    $display("%dth,g:%h",t,g);
                    f = e;
//                    $display("%dth,f:%h",t,f);
                    e = d + T1;
//                    $display("%dth,e:%h",t,e);
                    d = c;
//                    $display("%dth,d:%h",t,d);
                    c = b;
//                    $display("%dth,c:%h",t,c);
                    b = a;
//                    $display("%dth,b:%h",t,b);
                    a = T1 + T2;
                    $display("%dth,a:%h",t,a);
                end

                h[0] = h[0] + a;
                h[1] = h[1] + b;
                h[2] = h[2] + c;
                h[3] = h[3] + d;
                h[4] = h[4] + e;
                h[5] = h[5] + f;
                h[6] = h[6] + g;
                h[7] = h[7] + h_temp;
            digest_r = {h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]};
        end 
        
        always @(posedge clk or negedge rst_n) 
            if (!rst_n) begin
                state <= IDLE;
                done <= 1'b0;
            end
            else begin
//                valid_r <= valid;
                case(state)
                IDLE:begin
                    done <= 1'b0;
                    if(valid_r) begin    
                        state <= PROC;
                        done <= 1'b0;end
                end
                PROC:begin
                    state <= IDLE;
                    done <= 1'd1;
                    if(done)
                        done <= 0;
                end
                default:begin
                    state <= IDLE;
                    done <= 1'b0;
                end
                endcase
            end
                        
       assign valid_o = valid_r1;
     
 
endmodule    